﻿#region Copyright 2011 Mike Goatly
// This source is subject to the the MIT License (MIT)
// All rights reserved.
#endregion

namespace Lifti.Persistence
{
    using System.IO;
#if NETFX_CORE
    using System.Reflection;
#endif

    /// <summary>
    /// A generic persistence class for primitive types.
    /// </summary>
    /// <typeparam name="TItem">The type of the item.</typeparam>
    public class GenericPersistence<TItem> : TypePersistenceBase<TItem>
    {
        #region Private Variables
        /// <summary>
        /// The size of the type when written using a binary writer.
        /// </summary>
        private readonly short typeSize;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="GenericPersistence{TItem}"/> class.
        /// </summary>
        public GenericPersistence()
            : base(SerializationHelper.DetermineWriterMethod<TItem>(), SerializationHelper.DetermineReaderMethod<TItem>())
        {
#if !NETFX_CORE
            if (this.DataReader == null || this.DataWriter == null || !typeof(TItem).IsPrimitive)
#else
            if (this.DataReader == null || this.DataWriter == null || !typeof(TItem).GetTypeInfo().IsPrimitive)
#endif
            {
                throw new PersistenceException("Unable to automatically serialize type " + typeof(TItem).Name);
            }

            // Measure the size of the type
            MemoryStream stream = null;
            try
            {
                stream = new MemoryStream(16);
                using (var writer = new BinaryWriter(stream))
                {
                    stream = null;

                    this.DataWriter(writer, default(TItem));
                    this.typeSize = (short)writer.BaseStream.Length;
                    this.SizeReader = i => this.typeSize;
                }
            }
            finally
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
            }
        }
        #endregion
    }
}
